#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <SDL/SDL.h>

#include "primitives.h"
#include "clipboard.h"
#include "zombies.h"
#include "monsters.h"
#include "victims.h"
#include "player.h"
#include "cursor.h"
#include "display.h"
#include "level.h"
#include "items.h"
#include "font.h"
#include "gfx.h"

// SDL buffer that is show on screen
SDL_Surface *background;
SDL_Surface *screen;
SDL_Rect bgoffset;

SDL_Cursor *normalcursor;
SDL_Cursor *movecursor;
SDL_Cursor *dragcursor;

mouse_t mouse;

static SDL_Cursor *init_system_cursor(const char *image[])
{
    int i, row, col;
    unsigned char data[4*32];
    unsigned char mask[4*32];
    int hot_x, hot_y;

    i=-1;
    for(row=0;row<32;++row )
    {
        for(col=0;col<32;++col )
        {
            if(col%8)
            {
                data[i]<<=1;
                mask[i]<<=1;
            }
            else
            {
                ++i;
                data[i]=mask[i]=0;
            }
            
            switch(image[4+row][col])
            {
                case 'X':
                    data[i]|=0x01;
                    mask[i]|=0x01;
                    break;
                case '.':
                    mask[i]|=0x01;
                    break;
                case ' ':
                    break;
            }
        }
    }

    sscanf(image[4+row],"%d,%d",&hot_x,&hot_y);
    return SDL_CreateCursor(data,mask,32,32,hot_x,hot_y);
}

void initdisplay()
{
    screen=SDL_SetVideoMode(1024, 768, 32, SDL_DOUBLEBUF);
    if(screen == NULL)
    {
        printf("Unable to set video mode: %s\n", SDL_GetError());
        exit(0);
    }
    
    initfont();
    inititems();
    initvictims();
    initmonsters();
    initplayers();
    
    // set clipping bounds
    bgoffset.x=0; bgoffset.w=screen->w;
    bgoffset.y=0; bgoffset.h=screen->h;
    
    normalcursor=init_system_cursor(arrow);
    movecursor=init_system_cursor(arrow_move);
    dragcursor=init_system_cursor(arrow_drag);

    SDL_WM_SetCaption("ZamnED - Zombies Ate My Neighbors EDitor","ZamnED");
    SDL_SetCursor(normalcursor);
    renderscreen();
}

void renderscreen()
{
    // copy background image to screen buffer
    SDL_BlitSurface(background,&bgoffset,screen,NULL);

    // hide monsters/items/victims when editing
    if(st.bgedit)
    {
        drawtileborder();
        drawclipboard();
    }
    else
    {
        drawmonsters();
        drawvictims();
        drawplayers();
        drawitems();

        // show level name on top left corner
        drawtext(getlevelname(),10,10);
    }
    
    SDL_Flip(screen);
}

void dragbackgound()
{
    // adjust clipping position
    bgoffset.x-=mouse.xrel;
    bgoffset.y-=mouse.yrel;

    if(bgoffset.x<0) bgoffset.x=0;
    if(bgoffset.y<0) bgoffset.y=0;
    if(bgoffset.x>(background->w-screen->w)) bgoffset.x=background->w-screen->w;
    if(bgoffset.y>(background->h-screen->h)) bgoffset.y=background->h-screen->h;
}

void mousemotion()
{
    int x,y;
    
    // if object drag flag is set, then just do it
    if(mouse.drag!=0)
    {
        switch(mouse.drag)
        {
            case DRAG_ITEM:
                dragitem(mouse.objid,mouse.xrel,mouse.yrel);
                break;
            case DRAG_VICTIM:
                dragvictim(mouse.objid,mouse.xrel,mouse.yrel);
                break;
            case DRAG_MONSTER:
                dragmonster(mouse.objid,mouse.xrel,mouse.yrel);
                break;
            case DRAG_PLAYER:
                dragplayer(mouse.objid,mouse.xrel,mouse.yrel);
                break;
            case DRAG_BG:
                dragbackgound();
                break;
        }
        
        renderscreen();
        return;
    }
    else
    if(mouse.pressed && !mouse.drag)
    {
        // calculate relative mouse position
        x=(mouse.xpos+bgoffset.x)+8;
        y=(mouse.ypos+bgoffset.y)+8;

        // find wich object we have clicked
        if((mouse.objid=itemclicked(x,y))>-1)
        {
            mouse.drag=DRAG_ITEM;
            SDL_SetCursor(dragcursor);
        }
        else
        if((mouse.objid=victimclicked(x,y))>-1)
        {
            mouse.drag=DRAG_VICTIM;
            SDL_SetCursor(dragcursor);
        }
        else
        if((mouse.objid=monsterclicked(x,y))>-1)
        {
            mouse.drag=DRAG_MONSTER;
            SDL_SetCursor(dragcursor);
        }
        else
        if((mouse.objid=playerclicked(x,y))>-1)
        {
            mouse.drag=DRAG_PLAYER;
            SDL_SetCursor(dragcursor);
        }
        else
        {
            mouse.drag=DRAG_BG;
            SDL_SetCursor(movecursor);
        }
    }
}

void mainloop()
{
    SDL_Event event;

    while(SDL_PollEvent(&event))
    {
        switch(event.type)
        {
            case SDL_KEYDOWN:
            {
                switch(event.key.keysym.sym)
                {
                    case SDLK_z:
                        st.cbpos--;
                        break;
                    case SDLK_x:
                        st.cbpos++;
                        break;
                    case SDLK_c:
                        copytile();
                        break;
                    case SDLK_v:
                        pastetile();
                        break;
                    case SDLK_PAGEUP:
                        nexttile();
                        break;
                    case SDLK_PAGEDOWN:
                        previoustile();
                        break;
                    case SDLK_F1:
                        st.showgrid^=1;
                        fillbackground(); // redraw background
                        break;
                    case SDLK_F2:
                        printf("Rom saved.\n");
                        saverom();
                        break;
                    case SDLK_F11:
                        dumpbackground();
                        break;
                    case SDLK_F12:
                        dumptileset();
                        break;
                    case SDLK_ESCAPE:
                        st.quit=1;
                        break;

                    // GCC wont complain about unhandled enums...
                    default:
                    break;
                }
                
                // render screen after button action
                renderscreen();
            }
            case SDL_MOUSEMOTION:
            {
                mouse.xrel=event.motion.xrel;
                mouse.yrel=event.motion.yrel;
                mouse.xpos=event.motion.x;
                mouse.ypos=event.motion.y;
                mousemotion();
            }
            break;
            case SDL_MOUSEBUTTONDOWN:
            {
                if(event.button.button==1) // mouse grabbing
                {
                    // start grabbing
                    mouse.pressed=1;
                    st.bgedit=0;
                }
                else
                if(event.button.button==3) // edit tiles
                {
                    st.bgedit=1;

                    // get current clicked tile
                    st.tx=(bgoffset.x+mouse.xpos)/64;
                    st.ty=(bgoffset.y+mouse.ypos)/64;
                    st.tilecode=((st.ty*level.width)+st.tx)*2;
                }
                
                // mouse scroll tile up/down
                if(event.button.button==4) // up
                {
                    nexttile();
                }
                else
                if(event.button.button==5) // down
                {
                    previoustile();
                }
                
                // render screen after button action
                renderscreen();
            }
            break;
            case SDL_MOUSEBUTTONUP:
            {
                if(event.button.button==1)
                {
                    SDL_SetCursor(normalcursor);
                    mouse.pressed=0;
                    mouse.drag=DRAG_NONE;
                }
                
                // render screen after button action
                renderscreen();
            }
            break;
            case SDL_QUIT:
            {
                st.quit=1;
            }
            break;
        }
    }
    
    SDL_Delay(10);
}